package com.jiangxjsy.admin.service.impl;

import cn.hutool.core.collection.CollUtil;
import com.alibaba.fastjson.JSONObject;
import com.jiangxjsy.admin.client.CrmClient;
import com.jiangxjsy.admin.client.HrmClient;
import com.jiangxjsy.admin.mapper.AdminRoleMapper;
import com.jiangxjsy.admin.property.JwtProperty;
import com.jiangxjsy.admin.service.*;
import com.jiangxjsy.admin.support.AdminRoleSupport;
import com.jiangxjsy.admin.support.AdminUserSupport;
import com.jiangxjsy.core.common.AdminModule;
import com.jiangxjsy.core.common.AdminRoleType;
import com.jiangxjsy.core.constant.AdminCacheKey;
import com.jiangxjsy.core.constant.BasicConstant;
import com.jiangxjsy.core.constant.RedisCacheConstant;
import com.jiangxjsy.core.exception.AuthorizationException;
import com.jiangxjsy.core.jwt.JwtCore;
import com.jiangxjsy.core.redis.Redis;
import com.jiangxjsy.core.system.SystemCore;
import com.jiangxjsy.core.wrap.ResultCode;
import com.jiangxjsy.model.admin.bo.AdminRoleBO;
import com.jiangxjsy.model.admin.entity.AdminConfig;
import com.jiangxjsy.model.admin.entity.AdminMenu;
import com.jiangxjsy.model.admin.entity.AdminModelSort;
import com.jiangxjsy.model.admin.entity.AdminRole;
import com.jiangxjsy.model.admin.vo.AdminRoleVO;
import com.jiangxjsy.model.core.entity.UserMeta;
import org.springframework.stereotype.Service;
import org.springframework.util.StringUtils;

import javax.annotation.Resource;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.lang.reflect.InvocationTargetException;
import java.util.*;
import java.util.concurrent.TimeUnit;
import java.util.stream.Collectors;

/**
 * wukong-crm-master
 * 蒋胜宇
 * 2025/6/6 17:21
 */

@Service
public class AdminRoleServiceImpl implements AdminRoleService {
    @Resource
    private AdminRoleMapper adminRoleMapper;

    @Resource
    private AdminUserRoleService adminUserRoleService;

    @Resource
    private AdminMenuService adminMenuService;

    @Resource
    private AdminConfigService adminConfigService;

    @Resource
    private AdminModelSortService adminModelSortService;

    @Resource
    private AdminUserService adminUserService;

    @Resource
    private AdminRoleAuthService adminRoleAuthService;

    @Resource
    private AdminRoleSupport adminRoleSupport;

    @Resource
    private AdminUserSupport adminUserSupport;

    @Resource
    private HrmClient hrmClient;

    @Resource
    private CrmClient crmClient;

    @Resource
    private JwtProperty jwtProperty;

    @Resource
    private Redis redis;

    /**
     * 查询用户没有授权的菜单
     *
     * @param userId 用户 id
     * @return 菜单列表
     */
    @Override
    public List<String> queryNoAuthMenu(Long userId) {
        long superUserId = SystemCore.getSuperUser();
        AdminRole role = adminRoleMapper.selectByRemark("admin");
        Integer superRoleId = Math.toIntExact(role.getRoleId());

        List<Integer> roles = adminUserRoleService.queryUserRoleIds(userId);
        String key = userId.toString();
        List<String> noAuthMenuUrls = new ArrayList<>();
        if (userId == superUserId || roles.contains(superRoleId)) {
            redis.setEx(key, noAuthMenuUrls, RedisCacheConstant.MAX_CACHE_TIME, TimeUnit.MINUTES);
            return noAuthMenuUrls;
        }

        List<AdminMenu> adminMenus = adminMenuService.queryMenuList(userId);
        if (adminMenus.isEmpty()) {
            noAuthMenuUrls.add("/*/**");
            redis.setEx(key, noAuthMenuUrls, RedisCacheConstant.MAX_CACHE_TIME, TimeUnit.MINUTES);
            return noAuthMenuUrls;
        }

        List<Long> menuIdList = adminMenus.stream().map(AdminMenu::getMenuId).collect(Collectors.toList());
        List<AdminMenu> noAuthMenus = adminMenuService.queryNoAuthMenu(menuIdList);
        noAuthMenus.removeIf(node -> StringUtils.isEmpty(node.getRealmUrl()));
        if (!noAuthMenus.isEmpty()) {
            noAuthMenuUrls.addAll(noAuthMenus.stream().map(AdminMenu::getRealmUrl).collect(Collectors.toList()));
            redis.setEx(key, noAuthMenuUrls, RedisCacheConstant.MAX_CACHE_TIME, TimeUnit.MINUTES);
            return noAuthMenuUrls;
        }

        redis.setEx(key, noAuthMenuUrls, RedisCacheConstant.MAX_CACHE_TIME, TimeUnit.MINUTES);
        return noAuthMenuUrls;
    }

    /**
     * 角色权限
     *
     * @param request 请求
     * @param response 响应
     * @return JSONObject
     */
    @Override
    public JSONObject auth(HttpServletRequest request, HttpServletResponse response) {
        String token = request.getHeader(BasicConstant.TOKEN_NAME);
        UserMeta userMeta;
        try {
            userMeta = new JwtCore<>(UserMeta.class).analyzeToken(token, jwtProperty.getPublicKey());
        } catch (IllegalAccessException | NoSuchMethodException | InvocationTargetException | InstantiationException e) {
            throw new AuthorizationException(ResultCode.AuthorizationResultCode.AUTHORIZATION_LOGIN_ERR);
        }
        Long userId = userMeta.getUserId();

        String cacheKey = AdminCacheKey.USER_AUTH_CACHE_KET + userId;
        if (redis.hasKey(cacheKey)) {
            return redis.get(JSONObject.class, cacheKey);
        }

        List<AdminMenu> adminMenus = adminMenuService.queryMenuList(userId);
        List<AdminMenu> menus = adminMenuService.queryAll();
        for (int i = 0; i < menus.size(); i++) {
            if (Objects.equals(0L, menus.get(i).getParentId())) {
                adminMenus.add(menus.get(i));
                for (AdminMenu menu : menus) {
                    if (Objects.equals(menu.getParentId(), menus.get(i).getMenuId())) {
                        adminMenus.add(menu);
                    }
                }
            }
        }
        JSONObject jsonObject = adminRoleSupport.createMenu(new HashSet<>(adminMenus), 0L);
        List<AdminConfig> adminConfigList = adminConfigService.queryConfigListByName(
                (Object[]) AdminModule.getValues());

        if (jsonObject.containsKey(AdminModule.CRM.getModule())) {
            JSONObject authObject = new JSONObject();
            Long deptId = adminUserService.queryByUserId(userId).getDeptId();
            Map<String, Long> read = adminMenuService.queryPoolReadAuth(userId, deptId);

            if (adminUserSupport.isAdmin(userId) || read.get("adminNum") > 0 || read.get("userNum") > 0) {
                authObject.fluentPut("index", true).fluentPut("receive", true);
                if (adminUserSupport.isAdmin(userId) || read.get("adminNum") > 0) {
                    authObject.fluentPut("distribute", true).fluentPut("excelexport", true).fluentPut("delete", true);
                }
            }

            jsonObject.getJSONObject(AdminModule.CRM.getModule()).put("pool", authObject);

            List<?> data = crmClient.queryPoolNameListByAuth().getData();
            if (CollUtil.isEmpty(data)) {
                String crmKey = AdminModule.CRM.getModule();
                JSONObject crm = jsonObject.getJSONObject(crmKey);
                if (crm != null) {
                    crm.remove("pool");
                    jsonObject.put(crmKey, crm);
                }
            }
        }

        if (jsonObject.containsKey(AdminModule.JXC.getModule())) {
            String jxcKey = AdminModule.JXC.getModule();
            String biKey = AdminModule.BI.getModule();

            JSONObject jxc = jsonObject.getJSONObject(jxcKey);
            if (jxc.containsKey(biKey) && !jxc.getJSONObject(biKey).isEmpty()) {
                JSONObject jxcBi = jxc.getJSONObject(biKey);
                jxc.remove(biKey);
                if (jsonObject.containsKey(biKey)) {
                    JSONObject bi = jsonObject.getJSONObject(biKey);
                    bi.putAll(jxcBi);
                    jsonObject.put(biKey, bi);
                } else {
                    jsonObject.put(biKey, jxcBi);
                }
            }
        }

        adminConfigList.forEach(adminConfig -> {
            Long status = adminConfig.getStatus();

            if (AdminModule.CALL.getModule().equals(adminConfig.getName())) {
                JSONObject object = jsonObject.getJSONObject(AdminModule.BI.getModule());
                if (object != null && status != 1) {
                    object.remove(AdminModule.CALL.getModule());
                }
                return;
            }

            List<String> oaArray = Arrays.asList(
                    AdminModule.TASK_EXAMINE.getModule(),
                    AdminModule.LOG.getModule(),
                    AdminModule.BOOK.getModule(),
                    AdminModule.CALENDAR.getModule()
            );
            if (oaArray.contains(adminConfig.getName())) {
                if (!jsonObject.containsKey(AdminModule.OA.getModule())) {
                    jsonObject.put(AdminModule.OA.getModule(), new JSONObject());
                }
                JSONObject object = jsonObject.getJSONObject(AdminModule.OA.getModule());
                if (status == 0) {
                    object.remove(adminConfig.getName());
                } else {
                    if (!AdminModule.BOOK.getModule().equals(adminConfig.getName())) {
                        object.put(adminConfig.getName(), new JSONObject());
                    }
                }
                return;
            }

            if (Objects.equals(0L, adminConfig.getStatus())) {
                jsonObject.remove(adminConfig.getName());
            } else {
                if (!jsonObject.containsKey(adminConfig.getName())) {
                    jsonObject.put(adminConfig.getName(), new JSONObject());
                }
            }
        });

        String hrmKey = AdminModule.HRM.getModule();
        if (jsonObject.containsKey(hrmKey) && jsonObject.getJSONObject(hrmKey).isEmpty() && !adminUserSupport.isAdmin(userId)) {
            List<AdminRole> roles = queryRoleByRoleTypeAndUserId(9, userId);
            Boolean isInHrm = hrmClient.queryIsInHrm().getData();

            if (!isInHrm && CollUtil.isEmpty(roles)) {
                jsonObject.remove(hrmKey);
            }
        }

        redis.setEx(cacheKey, jsonObject, RedisCacheConstant.MAX_CACHE_TIME, TimeUnit.MINUTES);

        AdminModelSort one = adminModelSortService.queryByTypeAndUserId(1, userId);
        jsonObject.put("firstModel", one != null ? one.getModel() : "");

        return jsonObject;
    }

    /**
     * 通过角色类型和用户 id 查询角色列表
     *
     * @param type 角色类型
     * @param userId 用户 id
     * @return 角色列表
     */
    @Override
    public List<AdminRole> queryRoleByRoleTypeAndUserId(Integer type, Long userId) {
        return adminRoleMapper.selectRoleByRoleTypeAndUserId(type, userId);
    }

    /**
     * 获取角色类型列表
     *
     * @return 角色类型列表
     */
    @Override
    public List<Map<String, Object>> getRoleTypeList() {
        List<Map<String, Object>> data = new ArrayList<>(6);
        data.add(new JSONObject().fluentPut("name", "系统管理角色").fluentPut("roleType", 1));
        data.add(new JSONObject().fluentPut("name", "办公管理角色").fluentPut("roleType", 7));
        data.add(new JSONObject().fluentPut("name", "客户管理角色").fluentPut("roleType", 2));
        data.add(new JSONObject().fluentPut("name", "项目管理角色").fluentPut("roleType", 8));
        return data;
    }

    /**
     * 通过用户 id 查询角色列表
     *
     * @param userId 用户 id
     * @return 角色列表
     */
    @Override
    public List<AdminRole> queryRoleListByUserId(Long userId) {
        List<Integer> roleIdList = adminUserRoleService.queryUserRoleIds(userId);
        if (!roleIdList.isEmpty()) {
            return adminRoleMapper.selectByRoleIds(roleIdList);
        }
        return new ArrayList<>();
    }

    /**
     * 获取角色列表
     *
     * @param request 请求
     * @param response 响应
     * @return 角色列表
     */
    @Override
    public List<AdminRoleVO> getRoleList(HttpServletRequest request, HttpServletResponse response) {
        String token = request.getHeader(BasicConstant.TOKEN_NAME);
        UserMeta userMeta;
        try {
            userMeta = new JwtCore<>(UserMeta.class).analyzeToken(token, jwtProperty.getPublicKey());
        } catch (IllegalAccessException | NoSuchMethodException | InvocationTargetException | InstantiationException e) {
            throw new AuthorizationException(ResultCode.AuthorizationResultCode.AUTHORIZATION_LOGIN_ERR);
        }
        Long userId = userMeta.getUserId();

        List<AdminRoleVO> records = new ArrayList<>();
        boolean queryAllRole = adminRoleAuthService.isQueryAllRole(userId);
        if (queryAllRole) {
            return getAllRoleList();
        }

        Set<Integer> roleIds = adminRoleAuthService.queryAuthByUser(userId);
        for (AdminRoleType typeEnum : AdminRoleType.values()) {
            if (Arrays.asList(0, 3, 4, 5).contains(typeEnum.getRole())) {
                continue;
            }
            AdminRoleVO record = new AdminRoleVO();
            record.setName(adminRoleSupport.roleTypeCaseName(typeEnum.getRole()));
            record.setPid(typeEnum.getRole());
            List<AdminRoleBO> recordList = getRoleByType(typeEnum);
            recordList.removeIf(adminRole -> !roleIds.contains(Math.toIntExact(adminRole.getRoleId())));
            if(recordList.isEmpty()) {
                continue;
            }
            record.setList(recordList);
            records.add(record);
        }

        return records;
    }

    /**
     * 获取全部角色列表
     *
     * @return 全部角色列表
     */
    @Override
    public List<AdminRoleVO> getAllRoleList() {
        List<AdminRoleVO> records = new ArrayList<>();
        for (AdminRoleType typeEnum : AdminRoleType.values()) {
            if (Arrays.asList(0, 3, 4, 5).contains(typeEnum.getRole())) {
                continue;
            }
            AdminRoleVO record = new AdminRoleVO();
            record.setName(adminRoleSupport.roleTypeCaseName(typeEnum.getRole()));
            record.setPid(typeEnum.getRole());
            List<AdminRoleBO> recordList = getRoleByType(typeEnum);
            record.setList(recordList);
            records.add(record);
        }
        return records;
    }

    /**
     * 根据类型查询角色
     *
     * @param roleTypeEnum 角色类型
     * @return 角色列表
     */
    @Override
    public List<AdminRoleBO> getRoleByType(AdminRoleType roleTypeEnum) {
        List<AdminRoleBO> recordList = adminRoleMapper.selectByRoleType(roleTypeEnum.getRole());
        String realm;
        switch (roleTypeEnum) {
            case MANAGER:
                realm = "manage";
                break;
            case CUSTOMER_MANAGER:
                realm = "crm";
                break;
            case OA:
                realm = "oa";
                break;
            case PROJECT:
                realm = "project";
                break;
            case HRM:
                realm = "hrm";
                break;
            case JXC:
                realm = "jxc";
                break;
            default:
                return new ArrayList<>();
        }
        Integer pid = adminMenuService.queryMenuIdByParentIdAndRealm(0L, realm);
        recordList.forEach(record -> {
            Map<String, List<Integer>> map = new HashMap<>();
            List<Integer> data = adminRoleMapper.selectRoleMenu(Long.valueOf(pid), record.getRoleId());
            List<Integer> bi = adminRoleMapper.selectRoleMenu(2L, record.getRoleId());
            map.put("data", data);
            map.put("bi", bi);
            record.setRules(map);
        });
        return recordList;
    }

    /**
     * 根据类型查询角色
     *
     * @param type 角色类型
     * @return 角色列表
     */
    @Override
    public List<AdminRole> queryRoleByRoleType(Integer type) {
        return adminRoleMapper.selectByType(type);
    }
}
